﻿using KinonekoSoftware.CodariaDB.Documents.DataParts.Modules.RVE;
using KinonekoSoftware.CodariaDB.Documents.Theories.Chikara;

// ReSharper disable MemberCanBeMadeStatic.Global

#if WINDOWS
using System.Windows;
#else
using Avalonia;

#endif

namespace KinonekoSoftware.Studio.Models.Modules
{
    public sealed class RVEGroupPresenter : ModulePresenter, IBlockPresenter
    {
        private static readonly Thickness _Thickness = new Thickness(0, 0, 0, 32);
        private static readonly Thickness _Zero      = new Thickness(0);

        private readonly Block_RVE                           Target;
        private readonly Dictionary<string, ModulePresenter> _dictionary;

        public RVEGroupPresenter(Block_RVE target, IModuleMessageBus queue)
        {
            _dictionary = new Dictionary<string, ModulePresenter>();
            Queue       = queue ?? throw new ArgumentNullException(nameof(queue));
            Primary     = new ObservableCollection<ModulePresenter>();
            Secondary   = new ObservableCollection<ModulePresenter>();
            Hybrids     = new ObservableCollection<ModulePresenter>();

            Platform.GetEngine<
                TheoryEngine_Element,
                TheoryEngine_Rarity,
                TheoryEngine_Chikara>(out _,
                                      out var e,
                                      out var r,
                                      out var c);
            TheoryOfElement = e;
            TheoryOfRarity  = r;
            TheoryOfChikara = c;
            Initialize(target);
            Target = target;
        }

        private static void OnNumericChanged(string arg1, int arg2)
        {

        }


        private void Initialize(Block_RVE target)
        {
            target ??= CreateDummyInstance();


            Primary.AddMany(target.Part_Primary.Select(Select), true);
            Secondary.AddMany(target.Part_Secondary.Select(Select), true);
            Hybrids.AddMany(target.Part_Hybrid.Select(Select), true);

            var presenters = Primary.Concat(Secondary)
                                    .Concat(Hybrids)
                                    .Where(x => x is RVEDashboardPresenter or TextElementPresenter or NumericElementPresenter or SwitchElementPresenter);

            foreach (var presenter in presenters)
            {
                string metadata;

                if (presenter is RVEDashboardPresenter rve)
                {
                    metadata = rve.Metadata;
                }
                else if (presenter is NumericElementPresenter ne)
                {
                    metadata = ne.Metadata;
                }
                else
                {
                    metadata = ((TextElementPresenter)presenter).Metadata;
                }

                if (!string.IsNullOrEmpty(metadata))
                {
                    _dictionary.TryAdd(metadata, presenter);
                }
            }
        }


        private static Block_RVE CreateDummyInstance() => Block_RVE.CreateInstance();

        public override void DataSync(Variant variant)
        {
            if (!string.IsNullOrEmpty(variant.Metadata) &&
                _dictionary.TryGetValue(variant.Metadata, out var element))
            {
                element.DataSync(variant);
            }
        }

        public override string GetTitle() => CodariaSR.Module_RVE;

        public override bool IsMultipleVariants() => true;

        public override IEnumerable<Variant> GetVariants(string documentID)
        {
            foreach (var presenter in Primary)
            {
                if (presenter is null)
                {
                    continue;
                }

                yield return presenter.GetVariant(documentID);
            }

            foreach (var presenter in Secondary)
            {
                if (presenter is null)
                {
                    continue;
                }

                yield return presenter.GetVariant(documentID);
            }

            foreach (var presenter in Hybrids)
            {
                if (presenter is null)
                {
                    continue;
                }

                yield return presenter.GetVariant(documentID);
            }
        }

        public override Variant GetVariant(string documentID) => null;

        #region Select

        public ModulePresenter Select(IMainVisualRowElement block)
        {
            if (block is RVE_Dashboard rve_d)
            {
                return new RVEDashboardPresenter
                {
                    AssociatedObject = rve_d,
                    Queue            = Queue,
                    TopLevel         = this,
                };
            }

            if (block is RVE_Zodiac rve_z)
            {
                return new RVEZodiacPresenter
                {
                    AssociatedObject = rve_z,
                    Queue            = Queue,
                    TopLevel         = this,
                };
            }

            if (block is RVE_ChineseZodiac rve_cz)
            {
                return new RVEChineseZodiacPresenter()
                {
                    AssociatedObject = rve_cz,
                    Queue            = Queue,
                    TopLevel         = this,
                };
            }


            return null;
        }

        public ModulePresenter Select(RVE_Element block)
        {

            if (block is RVE_RarityRibbon rve_rb)
            {
                Rarity rarity;

                if (string.IsNullOrEmpty(rve_rb.RarityID))
                {
                    rarity          = TheoryOfRarity.Collection.FirstOrDefault();
                    rve_rb.RarityID = rarity?.Id;
                }
                else
                {
                    rarity = TheoryOfRarity.GetTheory(rve_rb.RarityID);

                    if (rarity is null)
                    {
                        rarity          = TheoryOfRarity.Collection.FirstOrDefault();
                        rve_rb.RarityID = rarity?.Id;
                    }
                }

                return new RVERarityRibbonPresenter(rve_rb, rarity)
                {
                    Queue    = Queue,
                    TopLevel = this,
                };
            }



            if (block is RVE_ElementRibbon rve_eb)
            {

                var element = TheoryOfElement.GetTheory(rve_eb.ElementID);

                if (string.IsNullOrEmpty(rve_eb.ElementID))
                {
                    rve_eb.ElementID = element?.Id;
                }

                return new RVEElementRibbonPresenter(rve_eb, element)
                {
                    Queue    = Queue,
                    TopLevel = this,
                };
            }


            return null;
        }

        public ModulePresenter Select(IHybridModuleBlock block)
        {
            if (block is Element_Numeric en)
            {
                return new NumericElementPresenter
                {
                    AssociatedObject = en,
                    OnValueChanged   = OnNumericChanged,
                    Queue            = Queue,
                    TopLevel         = this,
                };
            }

            if (block is Element_Text et)
            {
                return new TextElementPresenter
                {
                    AssociatedObject = et,
                    Queue            = Queue,
                    TopLevel         = this,
                };
            }

            var eo = (Element_Option)block;
            return new OptionElementPresenter
            {
                AssociatedObject = eo,
                Queue            = Queue,
                TopLevel         = this,
            };
        }

        #endregion

        public ModuleBlock GetBlock() => Target;

        protected override Task<bool> OnEditItem() => null;

        protected override void OnIndexChanged(int oldIndex, int newIndex)
        {
        }

        public void SetZodiac(bool enabled)
        {
            if (enabled)
            {

                if (Primary.Any(x => x is RVEZodiacPresenter))
                {
                    return;
                }

                var ribbon = new RVE_Zodiac
                {
                    Id = ID.Get(),
                };

                var p = Select((IMainVisualRowElement)ribbon);
                Target.Part_Primary.Add(ribbon);
                Primary.Add(p);
            }
            else
            {
                var index = Target.Part_Primary.IndexOf(x => x is RVE_Zodiac);
                Target.Part_Primary.RemoveAt(index);

                index = Primary.IndexOf(x => x is RVEZodiacPresenter);
                Primary.RemoveAt(index);
            }

            Queue?.OnNext(new SaveModuleMessage());
            RaiseUpdated(nameof(MarginOfSecondary));
        }

        public void SetChineseZodiac(bool enabled)
        {
            if (enabled)
            {

                if (Primary.Any(x => x is RVEChineseZodiacPresenter))
                {
                    return;
                }

                var ribbon = new RVE_ChineseZodiac
                {
                    Id = ID.Get(),
                };

                var p = Select((IMainVisualRowElement)ribbon);
                Target.Part_Primary.Add(ribbon);
                Primary.Add(p);
            }
            else
            {
                var index = Target.Part_Primary.IndexOf(x => x is RVE_ChineseZodiac);
                Target.Part_Primary.RemoveAt(index);

                index = Primary.IndexOf(x => x is RVEChineseZodiacPresenter);
                Primary.RemoveAt(index);
            }

            Queue?.OnNext(new SaveModuleMessage());
            RaiseUpdated(nameof(MarginOfSecondary));
        }


        public void SetElementRibbon(bool enabled)
        {
            if (enabled)
            {

                if (Secondary.Any(x => x is RVEElementRibbonPresenter))
                {
                    return;
                }

                var ribbon = new RVE_ElementRibbon
                {
                    Id = ID.Get(),
                };

                var p = Select(ribbon);
                Target.Part_Secondary
                      .Add(ribbon);
                Secondary.Add(p);
            }
            else
            {
                var index = Target.Part_Secondary.IndexOf(x => x is RVE_ElementRibbon);
                Target.Part_Secondary.RemoveAt(index);

                index = Secondary.IndexOf(x => x is RVEElementRibbonPresenter);
                Secondary.RemoveAt(index);
            }

            Queue?.OnNext(new SaveModuleMessage());
            RaiseUpdated(nameof(MarginOfSecondary));
        }

        public void SetRarityRibbon(bool enabled)
        {

            if (enabled)
            {

                if (Secondary.Any(x => x is RVERarityRibbonPresenter))
                {
                    return;
                }

                var element = new RVE_RarityRibbon
                {
                    Id = ID.Get(),
                };

                var p = Select(element);
                Target.Part_Secondary
                      .Add(element);
                Secondary.Add(p);
            }
            else
            {
                var index = Target.Part_Secondary.IndexOf(x => x is RVE_RarityRibbon);
                Target.Part_Secondary.RemoveAt(index);

                index = Secondary.IndexOf(x => x is RVERarityRibbonPresenter);
                Secondary.RemoveAt(index);
            }

            Queue?.OnNext(new SaveModuleMessage());
            RaiseUpdated(nameof(MarginOfSecondary));
        }

        public void NewPrimaryChild(RVEElementType type)
        {
            IMainVisualRowElement element = type switch
            {
                RVEElementType.Numeric => new Element_Numeric
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                },
                RVEElementType.Option => new Element_Option
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                    Items       = new List<Primitive_Option>()
                },
                RVEElementType.Text => new Element_Text
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                    Fallback    = TextSR.Parameter_Untitled,
                },
                RVEElementType.Zodiac => new RVE_Zodiac
                {
                    Id    = ID.Get(),
                    Value = Zodiac.Aries
                },
                RVEElementType.ChineseZodiac => new RVE_ChineseZodiac
                {
                    Id    = ID.Get(),
                    Value = ChineseZodiac.Tiger
                },
                _ => new RVE_Dashboard
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                    Value       = 30
                },
            };

            var p = Select(element);

            Target.Part_Primary.Add(element);
            Primary.Add(p);
            RaiseUpdated(nameof(MarginOfPrimary));
        }

        public void NewHybridChild(ModuleElementType type)
        {
            IHybridModuleBlock element = type switch
            {
                ModuleElementType.Numeric => new Element_Numeric
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                },
                ModuleElementType.Option => new Element_Option
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                    Items       = new List<Primitive_Option>()
                },
                _ => new Element_Text
                {
                    Id          = ID.Get(),
                    Title       = TextSR.Parameter_Untitled,
                    Description = TextSR.Parameter_Untitled,
                    Value       = TextSR.Parameter_Untitled,
                },
            };

            var p = Select(element);

            Target.Part_Hybrid.Add(element);
            Hybrids.Add(p);
        }

        public void MovePrimary(ModulePresenter element, bool up)
        {
            //
            //
            if (up)
            {
                Primary.ShiftUp(element);
            }
            else
            {
                Primary.ShiftDown(element);
            }


            if (element is RVEDashboardPresenter rve_dp)
            {
                if (up)
                {
                    Target.Part_Primary.ShiftUp(rve_dp.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(rve_dp.AssociatedObject);
                }
            }
            else if (element is RVEZodiacPresenter rve_z)
            {
                if (up)
                {
                    Target.Part_Primary.ShiftUp(rve_z.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(rve_z.AssociatedObject);
                }
            }
            else if (element is RVEChineseZodiacPresenter rve_cz)
            {

                if (up)
                {
                    Target.Part_Primary.ShiftUp(rve_cz.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(rve_cz.AssociatedObject);
                }
            }
            else if (element is TextElementPresenter tEP)
            {

                if (up)
                {
                    Target.Part_Primary.ShiftUp(tEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(tEP.AssociatedObject);
                }
            }
            else if (element is OptionElementPresenter oEP)
            {

                if (up)
                {
                    Target.Part_Primary.ShiftUp(oEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(oEP.AssociatedObject);
                }
            }
            else if (element is NumericElementPresenter nEP)
            {

                if (up)
                {
                    Target.Part_Primary.ShiftUp(nEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Primary.ShiftDown(nEP.AssociatedObject);
                }
            }
        }

        public void MoveHybrids(ModulePresenter element, bool up)
        {
            //
            //
            if (up)
            {
                Hybrids.ShiftUp(element);
            }
            else
            {
                Hybrids.ShiftDown(element);
            }


            if (element is TextElementPresenter tEP)
            {

                if (up)
                {
                    Target.Part_Hybrid.ShiftUp(tEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Hybrid.ShiftDown(tEP.AssociatedObject);
                }
            }
            else if (element is OptionElementPresenter oEP)
            {

                if (up)
                {
                    Target.Part_Hybrid.ShiftUp(oEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Hybrid.ShiftDown(oEP.AssociatedObject);
                }
            }
            else if (element is NumericElementPresenter nEP)
            {

                if (up)
                {
                    Target.Part_Hybrid.ShiftUp(nEP.AssociatedObject);
                }
                else
                {
                    Target.Part_Hybrid.ShiftDown(nEP.AssociatedObject);
                }
            }
        }

        public void RemovePrimary(ModulePresenter element)
        {
            //
            //
            Primary.Remove(element);


            if (element is RVEDashboardPresenter rve_dp)
            {
                Target.Part_Primary.Remove(rve_dp.AssociatedObject);
            }
            else if (element is RVEZodiacPresenter rve_z)
            {
                Target.Part_Primary.Remove(rve_z.AssociatedObject);
            }
            else if (element is RVEChineseZodiacPresenter rve_cz)
            {
                Target.Part_Primary.Remove(rve_cz.AssociatedObject);
            }
            else if (element is TextElementPresenter tEP)
            {
                Target.Part_Primary.Remove(tEP.AssociatedObject);
            }
            else if (element is OptionElementPresenter oEP)
            {
                Target.Part_Primary.Remove(oEP.AssociatedObject);
            }
            else if (element is NumericElementPresenter nEP)
            {
                Target.Part_Primary.Remove(nEP.AssociatedObject);
            }

            RaiseUpdated(nameof(MarginOfPrimary));
        }


        public void RemovePrimary()
        {
            //
            //
            Primary.Clear();
            Target.Part_Primary.Clear();
        }

        public void RemoveHybrids(ModulePresenter element)
        {

            //
            //
            Hybrids.Remove(element);


            if (element is TextElementPresenter tEP)
            {
                Target.Part_Hybrid.Remove(tEP.AssociatedObject);
            }
            else if (element is OptionElementPresenter oEP)
            {
                Target.Part_Hybrid.Remove(oEP.AssociatedObject);
            }
            else if (element is NumericElementPresenter nEP)
            {
                Target.Part_Hybrid.Remove(nEP.AssociatedObject);
            }
        }


        public void RemoveHybrids()
        {
            //
            //
            Hybrids.Clear();
            Target.Part_Hybrid.Clear();
        }

        public ObservableCollection<ModulePresenter> Primary   { get; }
        public ObservableCollection<ModulePresenter> Secondary { get; }
        public ObservableCollection<ModulePresenter> Hybrids   { get; }

        public TheoryEngine_Rarity  TheoryOfRarity  { get; }
        public TheoryEngine_Element TheoryOfElement { get; }
        public TheoryEngine_Chikara TheoryOfChikara { get; }

        public Thickness MarginOfPrimary   => Primary.Count   > 0 ? _Thickness : _Zero;
        public Thickness MarginOfSecondary => Secondary.Count > 0 ? _Thickness : _Zero;
    }
}